package com.cvtt.voice.gips;

import java.io.IOException;
import java.net.DatagramSocket;
import java.net.InetAddress;

import android.content.Context;
import android.util.Log;

import com.cvtt.voice.VoiceConfig;

public class GIPSVoice {

	// channel number
	private int voiceChannel = -1;

	// flags
	private boolean voERunning = false;

	private boolean isPlayout = true;

	// Constant
	private static final String TAG = "WEBRTC";
	private static final int RECEIVE_CODEC_FRAMERATE = 15;
	private static final int SEND_CODEC_FRAMERATE = 15;
	private static final int INIT_BITRATE = 500;

	private int volumeLevel = 255;

	// Audio settings
	private boolean enableAGC = true;
	private boolean enableAECM = true;
	private boolean enableNS = true;

	public GIPSVoice() {
	}

	public GIPSVoice(Context ctx) {
		AudioDeviceAndroid._context = ctx;
	}

	public void setContext(Context ctx) {
		AudioDeviceAndroid._context = ctx;
	}

	public boolean initLib() {
		if (VoiceConfig.LOG_ENABLE)
			Log.d("GIPS Voice", "Loading GIPS Voice...");
		try {
			System.loadLibrary("stlport_shared");
			System.loadLibrary("audio_preprocessing");
			System.loadLibrary("gipsvoice");

			if (VoiceConfig.LOG_ENABLE)
				Log.d("GIPS Voice", "Calling NativeInit()...");

			if (!NativeInit()) {
				if (VoiceConfig.LOG_ENABLE)
					Log.e("GIPS Voice", "Native init failed");
				return false;
				// throw new RuntimeException("Native init failed");
			}
			else {
				if (VoiceConfig.LOG_ENABLE)
					Log.d("GIPS Voice", "Native init successful");
			}

			if (0 > setup()) {
				if (VoiceConfig.LOG_ENABLE)
					Log.e("GIPSVoiceEngineAPI", "can't init VoiceEngine");
				// terminate();
				return false;
			}
		}
		catch (Error e) {
			if (VoiceConfig.LOG_ENABLE)
				Log.e("GIPS Voice Error:", "WARNING: Could not load libvoiceengine.so");
			e.printStackTrace();
			return false;
		}
		catch (Exception e) {
			if (VoiceConfig.LOG_ENABLE)
				Log.e("GIPS Voice Exception:", "WARNING: Could not load libvoiceengine.so");
			e.printStackTrace();
			return false;
		}

		return true;
	}

	private int setup() {
		// Create VoiceEngine
		// Error logging is done in native API wrapper
		Create(null);

		// Initialize
		if (0 != Init()) {
			if (VoiceConfig.LOG_ENABLE)
				Log.d(TAG, "VoE init failed");
			return -1;
		}

		// Modified by huah in 2012-08-27
		// Create channel
		// voiceChannel = CreateChannel();
		// if (0 > voiceChannel) {
		// if (CoreConfig.LOG_ENABLE)
		// Log.d(TAG, "VoE create channel failed");
		// return -1;
		// }

		// Suggest to use the voice call audio stream for hardware volume
		// controls
		// setVolumeControlStream(AudioManager.STREAM_VOICE_CALL);
		return 0;
	}

	// Modified by huah in 2012-08-28
	public synchronized void stop() {

		try {
			if (VoiceConfig.LOG_ENABLE)
				Log.d(TAG, "VoE StopVoiceEngine");

			// Modified by huah in 2012-08-28
			int curChannel = voiceChannel;

			// Added by huah in 2012-08-27
			if (curChannel != -1) {
				// Stop listen
				if (0 != StopListen(curChannel)) {
					if (VoiceConfig.LOG_ENABLE)
						Log.d(TAG, "VoE stop listen failed");
				}
				else {
					if (VoiceConfig.LOG_ENABLE)
						Log.d(TAG, "VoE stop listen success");
				}

				if (isPlayout) {
					// Stop playout
					if (0 != StopPlayout(curChannel)) {
						if (VoiceConfig.LOG_ENABLE)
							Log.d(TAG, "VoE stop playout failed");
					}
					else {
						if (VoiceConfig.LOG_ENABLE)
							Log.d(TAG, "VoE stop playout success");
					}
				}
				else {
					StopPlayingFileAsMicrophone(curChannel);
				}

				// Added by huah in 2012-08-27
				if (0 != StopSend(curChannel)) {
					if (VoiceConfig.LOG_ENABLE)
						Log.d(TAG, "VoE stop send failed");
				}
				else {
					if (VoiceConfig.LOG_ENABLE)
						Log.d(TAG, "VoE stop send success!");
				}

				// Modified by huah in 2012-08-27
				// Stop send
				// if (0 != StopSend(voiceChannel)) {
				// if (CoreConfig.LOG_ENABLE)
				// Log.d(TAG, "VoE stop send failed");
				// }
				//
				// // Stop listen
				// if (0 != StopListen(voiceChannel)) {
				// if (CoreConfig.LOG_ENABLE)
				// Log.d(TAG, "VoE stop listen failed");
				// }

				// Added by huah in 2012-08-27
				if (curChannel >= 0) {
					if (0 != DeleteChannel(curChannel)) {
						if (VoiceConfig.LOG_ENABLE)
							Log.d(TAG, "VoE delete channel failed!");
					}
					else {
						if (VoiceConfig.LOG_ENABLE)
							Log.d(TAG, "VoE delete channel success!");
					}

				}
			}

		}
		catch (Error e) {
			if (VoiceConfig.LOG_ENABLE)
				Log.e("GIPS Voice Error:", "WARNING: stop error!");
			e.printStackTrace();
		}
		catch (Exception e) {
			if (VoiceConfig.LOG_ENABLE)
				Log.e("GIPS Voice Exception:", "WARNING: stop failed!");
			e.printStackTrace();
		}

		// Modified by huah in 2012-08-28
		// voiceChannel = -1;

		isPlayout = true;
		voERunning = false;

	}

	public int start(int localPort, String remoteAddr, int remotePort, int payloadType) {
		return start(localPort, remoteAddr, remotePort, payloadType, true);
	}

	public int start(int localPort, String remoteAddr, int remotePort, int payloadType, boolean playout) {

		// Modified by huah in 2012-08-28
		// if (voERunning) {
		// if (CoreConfig.LOG_ENABLE)
		// Log.d(TAG, "GIPSVoiceEngineAPI:start:stop()");
		// stop();
		// }

		// Added by huah in 2012-08-27
		// System.gc();

		isPlayout = playout;

		// Added by huah in 2012-08-27
		voiceChannel = CreateChannel();
		if (VoiceConfig.LOG_ENABLE)
			Log.d(TAG, "VoE Create Channel:" + voiceChannel);
		if (0 > voiceChannel) {
			if (VoiceConfig.LOG_ENABLE)
				Log.d(TAG, "VoE create channel failed");
			return -1;
		}

		if (VoiceConfig.LOG_ENABLE)
			Log.e(TAG, "VoE StartVoiceEngine" + voiceChannel + "V" + localPort + "V" + remoteAddr + "V" + remotePort + "V" + payloadType);

		if (0 != SetECStatus(enableAECM)) {
			if (VoiceConfig.LOG_ENABLE)
				Log.d(TAG, "VoE set EC Status failed");
		}

		if (0 != SetAGCStatus(enableAGC)) {
			if (VoiceConfig.LOG_ENABLE)
				Log.d(TAG, "VoE set AGC Status failed");
		}

		if (0 != SetNSStatus(enableNS)) {
			if (VoiceConfig.LOG_ENABLE)
				Log.d(TAG, "VoE set NS Status failed");
		}

		// set volume to default value
		// Modified by huah in 2012-08-27
		// if (0 != SetSpeakerVolume(volumeLevel)) {
		// if (CoreConfig.LOG_ENABLE)
		// Log.d(TAG, "VoE set speaker volume failed");
		// }

		// Start playout
		if (playout) {
			if (0 != StartPlayout(voiceChannel)) {
				if (VoiceConfig.LOG_ENABLE)
					Log.d(TAG, "VoE start playout failed");
			}
		}

		// Set local receiver
		if (0 != SetLocalReceiver(voiceChannel, localPort)) {
			if (VoiceConfig.LOG_ENABLE)
				Log.d(TAG, "VoE set local receiver failed");
		}

		if (0 != StartListen(voiceChannel)) {
			if (VoiceConfig.LOG_ENABLE)
				Log.d(TAG, "VoE start listen failed");
		}

		if (VoiceConfig.LOG_ENABLE)
			Log.d(TAG, "VoE start listen end");

		if (0 != SetSendDestination(voiceChannel, remotePort, remoteAddr)) {
			if (VoiceConfig.LOG_ENABLE)
				Log.d(TAG, "VoE set send  destination failed");
		}
		if (0 != SetSendCodec(voiceChannel, payloadType)) {
			if (VoiceConfig.LOG_ENABLE)
				Log.d(TAG, "VoE set send codec failed");
		}

		if (0 != StartSend(voiceChannel)) {
			if (VoiceConfig.LOG_ENABLE)
				Log.d(TAG, "VoE start send failed");
		}

		if (VoiceConfig.LOG_ENABLE) {
			Log.d(TAG, "VoE start send end");

			Log.d(TAG, "VoE start end");
		}

		voERunning = true;
		return 0;
	}

	public void startPlayout() {
		if (isPlayout)
			return;
		isPlayout = true;
		if (voiceChannel != -1) {
			if (0 != StartPlayout(voiceChannel)) {
				if (VoiceConfig.LOG_ENABLE)
					Log.d(TAG, "VoE start playout failed");
			}
		}
	}

	public void setVolumeRaise(double r) {
		SetVolumeRaise(voiceChannel, r);
	}

	private void RouteAudio(boolean enableSpeaker) {
		/**
		 * int sdkVersion = Integer.parseInt(android.os.Build.VERSION.SDK); if (sdkVersion >= 5) { AudioManager am = (AudioManager) this.getSystemService(Context.AUDIO_SERVICE); am.setSpeakerphoneOn(enableSpeaker); } else { if (0 != VoEAndroidAPI.SetLoudspeakerStatus(enableSpeaker)) { Log.d(TAG, "VoE set louspeaker status failed"); } }
		 */
	}

	public void terminate() {
		if (VoiceConfig.LOG_ENABLE)
			Log.d(TAG, "StopAll");
		stop();
		if (voiceChannel >= 0) {
			if (0 != DeleteChannel(voiceChannel)) {
				if (VoiceConfig.LOG_ENABLE)
					Log.d(TAG, "VoE delete channel failed");
			}
			voiceChannel = -1;
		}
		// Terminate
		if (0 != Terminate()) {
			if (VoiceConfig.LOG_ENABLE)
				Log.d(TAG, "VoE terminate failed");
		}
	}

	public int checkPortAvailable(int port) {
		DatagramSocket s = null;
		int availablePort = port;

		for (; availablePort < 65535; availablePort++) {

			try {
				s = new DatagramSocket(availablePort, InetAddress.getLocalHost());
				s.close();
				return availablePort;
			}
			catch (IOException e) {
				continue;
			}

		}
		return -1;
	}

	public void playTone(String filename) {
		// String filename = getToneFileName();
		if ((filename != null) && (!filename.equals("")))
			StartPlayingFileAsMicrophone(voiceChannel, filename, true);
	}

	public void stopPlayTone() {
		// isPlayout = true;
		StopPlayingFileAsMicrophone(voiceChannel);
	}

	public void muteMic(boolean mute) {
		SetInputMute(voiceChannel, mute);
	}

	// API Native
	private native boolean NativeInit();

	// Voice Engine API
	// Create and Delete functions
	public native boolean Create(Context context);

	// public native boolean Create();

	public native boolean Delete();

	// Initialization and Termination functions
	public native int Init();

	public native int Terminate();

	// Channel functions
	public native int CreateChannel();

	public native int DeleteChannel(int channel);

	// Receiver & Destination functions
	public native int SetLocalReceiver(int channel, int port);

	public native int SetSendDestination(int channel, int port, String ipaddr);

	// Media functions
	public native int StartListen(int channel);

	public native int StartPlayout(int channel);

	public native int StartSend(int channel);

	public native int StopListen(int channel);

	public native int StopPlayout(int channel);

	public native int StopSend(int channel);

	// Volume
	public native int SetSpeakerVolume(int volume);

	public native int GetSpeakerVolume();

	public native int SetMicrophoneVolume(int volume);

	public native int GetMicrophoneVolume();

	public native int SetInputMute(int channel, boolean enable);

	public native boolean GetInputMute(int channel);

	// Hardware
	public native int SetLoudspeakerStatus(boolean enable);

	// Playout file locally
	public native int StartPlayingFileLocally(int channel, String fileName, boolean loop);

	public native int StopPlayingFileLocally(int channel);

	// Play file as microphone
	public native int StartPlayingFileAsMicrophone(int channel, String fileName, boolean loop);

	public native int StopPlayingFileAsMicrophone(int channel);

	// Codec-setting functions
	public native int NumOfCodecs();

	public native String[] GetCodecs();

	// set send codec, payloadType: 0:PCMU 8:PCMA 18:G729
	public native int SetSendCodec(int channel, int payloadType);

	// Raise the playout PCM Data
	public native int SetVolumeRaise(int channel, double volRaise);

	// VE funtions
	public native int SetECStatus(boolean enable);

	public native int SetAGCStatus(boolean enable);

	public native int SetNSStatus(boolean enable);
}